home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume22 / nn6.4 / part16 < prev    next >
Encoding:
Internet Message Format  |  1990-06-07  |  54.2 KB

  1. Subject:  REPOST v22i052:  NN Newsreader, release 6.4, Part16/21
  2. Newsgroups: comp.sources.unix
  3. Approved: rsalz@uunet.UU.NET
  4. X-Checksum-Snefru: f91ab175 078d3c43 4ad0d623 0d7e5c9d
  5.  
  6. Submitted-by: "Kim F. Storm" <storm@texas.dk>
  7. Posting-number: Volume 22, Issue 51
  8. Archive-name: nn6.4/part16
  9.  
  10. #! /bin/sh
  11. # This is a shell archive.  Remove anything before this line, then feed it
  12. # into a shell via "sh file" or similar.  To overwrite existing files,
  13. # type "sh file -c".
  14. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  15. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  16. # Contents:  collect.c doc/NEWS-6.4 doc/NNTP inews/clientlib.c prefix.c
  17. # Wrapped by rsalz@litchi.bbn.com on Fri May 11 12:43:14 1990
  18. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  19. echo If this archive is complete, you will see the following message:
  20. echo '          "shar: End of archive."'
  21. if test -f 'collect.c' -a "${1}" != "-c" ; then 
  22.   echo shar: Will not clobber existing file \"'collect.c'\"
  23. else
  24.   echo shar: Extracting \"'collect.c'\" \(11227 characters\)
  25.   sed "s/^X//" >'collect.c' <<'END_OF_FILE'
  26. X/*
  27. X *    (c) Copyright 1990, Kim Fabricius Storm.  All rights reserved.
  28. X *
  29. X *    Collect and save article information in database.
  30. X */
  31. X
  32. X#include "config.h"
  33. X#include "db.h"
  34. X#include "news.h"
  35. X
  36. X#define COUNT_RE_REFERENCES    /* no of >>> depends on Reference: line */
  37. X
  38. Xexport int ignore_bad_articles = 1;    /* no Newsgroups: line */
  39. Xexport int remove_bad_articles = 0;
  40. Xexport time_t max_article_age = 0;
  41. X
  42. Ximport int trace, debug_mode;
  43. X
  44. Xextern time_stamp pack_date();
  45. X
  46. Xstatic long bad_count;
  47. X
  48. Xstatic FILE *ix, *data;
  49. X
  50. Xstatic do_auto_archive(gh, f, num)
  51. Xgroup_header *gh;
  52. Xregister FILE *f;
  53. Xarticle_number num;
  54. X{
  55. X    char line[200];
  56. X    article_number last;
  57. X    register FILE *arc;
  58. X    register int c;
  59. X    off_t start;
  60. X    static char *arc_header = "Archived-Last: ";
  61. X    /* Header format: Archived-Last: 88888888 group.name */
  62. X    /* Fixed constants length == 15 and offset == 24 are used below */
  63. X
  64. X    arc = open_file(gh->archive_file, OPEN_READ);
  65. X    last = 0;
  66. X    start = 0;
  67. X    if (arc != NULL) {
  68. X    while (fgets(line, 200, arc) != NULL) {
  69. X        if (strncmp(line, arc_header, 15)) {
  70. X        log_entry('E', "%s not archive for %s\n",
  71. X              gh->archive_file, gh->group_name);
  72. X        gh->master_flag &= ~M_AUTO_ARCHIVE;
  73. X        fclose(arc);
  74. X        return;
  75. X        }
  76. X        if (strncmp(line + 24, gh->group_name, gh->group_name_length)) {
  77. X        start = ftell(arc);
  78. X        continue;
  79. X        }
  80. X        last = atol(line + 15);
  81. X        break;
  82. X    }
  83. X    fclose(arc);
  84. X    arc = NULL;
  85. X    }
  86. X
  87. X    if (last >= num) return;
  88. X
  89. X    arc = open_file(gh->archive_file, last > 0 ? OPEN_UPDATE : OPEN_CREATE);
  90. X    if (arc == NULL) {
  91. X    log_entry('E', "Cannot create archive file: %s\n", gh->archive_file);
  92. X    gh->master_flag &= ~M_AUTO_ARCHIVE;
  93. X    return;
  94. X    }
  95. X
  96. X    fseek(arc, start, 0);
  97. X    fprintf(arc, "%s%8ld %s\n", arc_header, (long)num, gh->group_name);
  98. X    fseek(arc, (off_t)0, 2);
  99. X
  100. X    fseek(f, (off_t)0, 0);
  101. X    while ((c = getc(f)) != EOF) putc(c, arc);
  102. X    putc(NL, arc);
  103. X    fclose(arc);
  104. X}
  105. X
  106. Xstatic build_hdr(type)
  107. Xint type;
  108. X{
  109. X    register char *name, *subj;
  110. X    int re;
  111. X
  112. X    db_data.dh_type = type;
  113. X
  114. X    if (type == DH_SUB_DIGEST) {
  115. X
  116. X    name = digest.dg_from;
  117. X    subj = digest.dg_subj;
  118. X
  119. X    db_hdr.dh_lines = digest.dg_lines;
  120. X
  121. X    db_hdr.dh_hpos = digest.dg_hpos;
  122. X    db_hdr.dh_fpos = (int16)(digest.dg_fpos - db_hdr.dh_hpos);
  123. X    db_hdr.dh_lpos = digest.dg_lpos;
  124. X
  125. X    db_hdr.dh_date = pack_date(digest.dg_date ? digest.dg_date : news.ng_date);
  126. X    } else {
  127. X
  128. X    if (!news.ng_from) news.ng_from = news.ng_reply;
  129. X
  130. X    name = news.ng_from;
  131. X    subj = news.ng_subj;
  132. X
  133. X    db_hdr.dh_lines = news.ng_lines;
  134. X
  135. X    db_hdr.dh_hpos = 0;
  136. X    db_hdr.dh_fpos = (int16)(news.ng_fpos);
  137. X    db_hdr.dh_lpos = news.ng_lpos;
  138. X
  139. X    db_hdr.dh_date = pack_date(news.ng_date);
  140. X    }
  141. X
  142. X    if (name) {
  143. X    db_hdr.dh_sender_length = pack_name(db_data.dh_sender, name, NAME_LENGTH);
  144. X    } else
  145. X        db_hdr.dh_sender_length = 0;
  146. X
  147. X    if (type == DH_DIGEST_HEADER) {
  148. X    db_hdr.dh_subject_length = 1;
  149. X    db_data.dh_subject[0] = '@';
  150. X    } else
  151. X    db_hdr.dh_subject_length = 0;
  152. X
  153. X    db_hdr.dh_subject_length +=
  154. X    pack_subject(db_data.dh_subject + db_hdr.dh_subject_length, subj, &re,
  155. X             DBUF_SIZE);
  156. X
  157. X#ifdef COUNT_RE_REFERENCES
  158. X    if (re) re = 0x80;
  159. X    if (news.ng_ref) {
  160. X    for (name = news.ng_ref; *name; name++) {
  161. X        if ((re & 0x7f) == 0x7f) break;
  162. X        if (*name == '<') re++;
  163. X    }
  164. X    }
  165. X#endif
  166. X    db_hdr.dh_replies = re;
  167. X
  168. X    if (db_write_art(data) < 0) write_error();
  169. X}
  170. X
  171. X
  172. Xstatic collect_article(gh, art_num)
  173. Xregister group_header *gh;
  174. Xarticle_number art_num;
  175. X{
  176. X    FILE *art_file;
  177. X    news_header_buffer nhbuf, dgbuf;
  178. X    article_header art_hdr;
  179. X    int mode, count;
  180. X    cross_post_number *cp_ptr;
  181. X    long age;
  182. X
  183. X    count = 0;
  184. X
  185. X    db_hdr.dh_number = art_num;
  186. X
  187. X    /* get article header */
  188. X
  189. X    art_hdr.a_number = art_num;
  190. X    art_hdr.hpos = (off_t)0;
  191. X    art_hdr.lpos = (off_t)0;
  192. X    art_hdr.flag = 0;
  193. X
  194. X    mode = FILL_NEWS_HEADER | FILL_OFFSETS | SKIP_HEADER;
  195. X    if ((gh->master_flag & (M_CONTROL | M_NEVER_DIGEST | M_ALWAYS_DIGEST)) == 0)
  196. X    mode |= DIGEST_CHECK;
  197. X#ifdef NNTP
  198. X    if ((gh->master_flag & M_ALWAYS_DIGEST) == 0)
  199. X    mode |= LAZY_BODY;
  200. X#endif
  201. X    if ((art_file = open_news_article(&art_hdr, mode, nhbuf, (char *)NULL)) == NULL) {
  202. X
  203. X#ifdef NNTP
  204. X    import nntp_failed;
  205. X
  206. X    if (nntp_failed) {
  207. X        /*
  208. X         * connection to nntp_server is broken
  209. X         * stop collection of articles immediately
  210. X         */
  211. X        return -1;
  212. X    }
  213. X#endif
  214. X    /*
  215. X     * it is not really necessary to save anything in the data file
  216. X     * we simply use the index file to get the *first* available article
  217. X     */
  218. X    return 0;
  219. X    }
  220. X
  221. X    if (art_file == (FILE *)1) {    /* empty file */
  222. X    if (!ignore_bad_articles) return 0;
  223. X    news.ng_groups = NULL;
  224. X    art_file = NULL;
  225. X    } else
  226. X    if ( max_article_age &&    /* == 0 if use_nntp */
  227. X        (gh->master_flag & M_INCLUDE_OLD) == 0 &&
  228. X        (age = m_time(art_file)) < max_article_age) {
  229. X
  230. X        if (remove_bad_articles) unlink(group_path_name);
  231. X
  232. X        log_entry('O', "%sold article (%ld days): %s/%ld",
  233. X              remove_bad_articles ? "removed " : "",
  234. X              (cur_time() - age) / (24 * 60 * 60),
  235. X              current_group->group_name, (long)art_num);
  236. X        bad_count++;
  237. X        fclose(art_file);
  238. X        return 0;
  239. X    }
  240. X
  241. X    if (ignore_bad_articles && news.ng_groups == NULL) {
  242. X    char *rem = "";
  243. X
  244. X    if (!use_nntp && remove_bad_articles) {
  245. X        unlink(group_path_name);
  246. X        rem = "removed ";
  247. X    }
  248. X
  249. X    log_entry('B', "%sbad article: %s/%ld", rem,
  250. X          current_group->group_name, (long)art_num);
  251. X    if (art_file != NULL) fclose(art_file);
  252. X    bad_count++;
  253. X    return 0;
  254. X    }
  255. X
  256. X    /* map cross-postings into a list of group numbers */
  257. X
  258. X    db_hdr.dh_cross_postings = 0;
  259. X
  260. X    if (gh->master_flag & M_CONTROL) {
  261. X    /* we cannot trust the Newsgroups: line in the control group */
  262. X    /* so we simply ignore it (i.e. use "Newsgroups: control") */
  263. X    goto dont_digest;
  264. X    }
  265. X
  266. X    if (news.ng_groups) {
  267. X    char *curg, *nextg;
  268. X    group_header *gh1;
  269. X
  270. X    for (nextg = news.ng_groups, cp_ptr = db_data.dh_cross; *nextg; ) {
  271. X        curg = nextg;
  272. X
  273. X        if (nextg = strchr(curg, ','))
  274. X        *nextg++ = NUL;
  275. X        else
  276. X        nextg = "";
  277. X
  278. X        if (strcmp(gh->group_name, curg) == 0)
  279. X        gh1 = gh;
  280. X        else
  281. X        if ((gh1 = lookup(curg)) == NULL) continue;
  282. X
  283. X        *cp_ptr++ = NETW_CROSS_EXT(gh1->group_num);
  284. X        if (++db_hdr.dh_cross_postings == DBUF_SIZE) break;
  285. X    }
  286. X    }
  287. X
  288. X    if (db_hdr.dh_cross_postings == 1)
  289. X    db_hdr.dh_cross_postings = 0;    /* only current group */
  290. X
  291. X    if (gh->master_flag & M_NEVER_DIGEST)
  292. X    goto dont_digest;
  293. X
  294. X    /* split digest */
  295. X
  296. X    if ((gh->master_flag & M_ALWAYS_DIGEST) || (news.ng_flag & N_DIGEST)) {
  297. X    int any = 0, cont = 1;
  298. X
  299. X    skip_digest_body(art_file);
  300. X
  301. X    while (cont && (cont = get_digest_article(art_file, dgbuf)) >= 0) {
  302. X
  303. X        if (any == 0) {
  304. X        build_hdr(DH_DIGEST_HEADER);    /* write DIGEST_HEADER */
  305. X        count++;
  306. X        db_hdr.dh_cross_postings = 0;    /* no cross post in sub */
  307. X        any++;
  308. X        }
  309. X        build_hdr(DH_SUB_DIGEST);    /* write SUB_DIGEST */
  310. X        count++;
  311. X    }
  312. X
  313. X    if (any) goto finish;
  314. X    }
  315. X
  316. X    /* not a digest */
  317. X
  318. X dont_digest:
  319. X
  320. X    build_hdr(DH_NORMAL);    /* normal article */
  321. X    count++;
  322. X
  323. Xfinish:
  324. X
  325. X    if (gh->master_flag & M_AUTO_ARCHIVE)
  326. X    do_auto_archive(gh, art_file, art_num);
  327. X
  328. X    fclose(art_file);
  329. X
  330. X    return count;
  331. X}
  332. X
  333. X
  334. X/*
  335. X *    Collect unread articles in current group
  336. X *
  337. X *    On entry, init_group has been called to setup the proper environment
  338. X */
  339. X
  340. Xstatic long collect_group(gh)
  341. Xregister group_header *gh;
  342. X{
  343. X    long article_count, temp, obad;
  344. X    article_number start_collect;
  345. X
  346. X    if (gh->last_db_article == 0) {
  347. X    gh->first_db_article = gh->first_a_article;
  348. X    gh->last_db_article = gh->first_db_article - 1;
  349. X    }
  350. X
  351. X    if (gh->last_db_article >= gh->last_a_article) return 0;
  352. X
  353. X    if (gh->index_write_offset) {
  354. X    ix = open_data_file(gh, 'x', OPEN_UPDATE|MUST_EXIST);
  355. X    fseek(ix, gh->index_write_offset, 0);
  356. X    } else
  357. X        ix = open_data_file(gh, 'x', OPEN_CREATE|MUST_EXIST);
  358. X
  359. X    if (gh->data_write_offset) {
  360. X    data = open_data_file(gh, 'd', OPEN_UPDATE|MUST_EXIST);
  361. X    fseek(data, gh->data_write_offset, 0);
  362. X    } else
  363. X    data = open_data_file(gh, 'd', OPEN_CREATE|MUST_EXIST);
  364. X
  365. X    article_count = 0;
  366. X    start_collect = gh->last_db_article+1;
  367. X
  368. X    if (debug_mode) {
  369. X    printf("\t\t%s (%ld..%ld)\r",
  370. X           gh->group_name, start_collect, gh->last_a_article);
  371. X    fl;
  372. X    }
  373. X    bad_count = obad = 0;
  374. X
  375. X    while (gh->last_db_article < gh->last_a_article) {
  376. X    if (s_hangup) break;
  377. X    gh->last_db_article++;
  378. X    if (debug_mode) {
  379. X        printf("\r%ld", gh->last_db_article);
  380. X        if (obad != bad_count) printf("\t%ld", bad_count);
  381. X        obad = bad_count;
  382. X        fl;
  383. X    }
  384. X    gh->data_write_offset = ftell(data);
  385. X#ifdef NNTP
  386. X    gh->index_write_offset = ftell(ix);
  387. X#endif
  388. X    temp = collect_article(gh, gh->last_db_article);
  389. X#ifdef NNTP
  390. X    if (temp < 0) {
  391. X        /* connection failed, current article is not collected */
  392. X        gh->last_db_article--;
  393. X        article_count = -1;
  394. X        goto out;
  395. X    }
  396. X#endif
  397. X#ifndef RENUMBER_DANGER
  398. X    if (temp == 0 && gh->data_write_offset == (off_t)0) {
  399. X        gh->first_db_article = gh->last_db_article + 1;
  400. X        continue;
  401. X    }
  402. X#endif
  403. X    if (!db_write_offset(ix, &(gh->data_write_offset)))
  404. X        write_error();
  405. X    article_count += temp;
  406. X    }
  407. X
  408. X    if (start_collect < gh->first_db_article)
  409. X    start_collect = gh->first_db_article;
  410. X
  411. X    if (trace && start_collect <= gh->last_db_article)
  412. X    log_entry('T', "Col %s (%d to %d) %d",
  413. X          gh->group_name,
  414. X          start_collect, gh->last_db_article,
  415. X          article_count);
  416. X
  417. X    if (debug_mode)
  418. X    printf("\nCol %s (%d to %d) %d",
  419. X           gh->group_name,
  420. X           start_collect, gh->last_db_article,
  421. X           article_count);
  422. X
  423. X    gh->data_write_offset = ftell(data);
  424. X    gh->index_write_offset = ftell(ix);
  425. X
  426. X out:
  427. X    fclose(data);
  428. X    fclose(ix);
  429. X
  430. X    if (debug_mode) putchar(NL);
  431. X
  432. X    return article_count;
  433. X}
  434. X
  435. X
  436. Xdo_collect()
  437. X{
  438. X    register group_header *gh;
  439. X    long col_article_count, temp;
  440. X    int col_group_count;
  441. X    time_t start_time;
  442. X
  443. X    start_time = cur_time();
  444. X    col_article_count = col_group_count = 0;
  445. X    current_group = NULL; /* for init_group */
  446. X    temp = 0;
  447. X
  448. X    Loop_Groups_Header(gh) {
  449. X    if (s_hangup) {
  450. X        temp = -1;
  451. X        break;
  452. X    }
  453. X
  454. X    if (gh->master_flag & M_IGNORE_GROUP) continue;
  455. X
  456. X    if (gh->master_flag & M_MUST_CLEAN)
  457. X        clean_group(gh);
  458. X
  459. X    if (gh->last_db_article == gh->last_a_article) {
  460. X        if (gh->master_flag & M_BLOCKED) goto unblock_group;
  461. X        continue;
  462. X    }
  463. X
  464. X    if (!init_group(gh)) {
  465. X        if ((gh->master_flag & M_NO_DIRECTORY) == 0) {
  466. X        log_entry('R', "%s: no directory", gh->group_name);
  467. X        gh->master_flag |= M_NO_DIRECTORY;
  468. X        }
  469. X        gh->last_db_article = gh->last_a_article;
  470. X        gh->first_db_article = gh->last_a_article;    /* OBS: not first */
  471. X        gh->master_flag &= ~(M_EXPIRE | M_BLOCKED);
  472. X        db_write_group(gh);
  473. X        continue;
  474. X    }
  475. X
  476. X    if (gh->master_flag & M_NO_DIRECTORY) {
  477. X        /* The directory has been created now */
  478. X        gh->master_flag &= ~M_NO_DIRECTORY;
  479. X        clean_group(gh);
  480. X    }
  481. X
  482. X    temp = collect_group(gh);
  483. X#ifdef NNTP
  484. X    if (temp < 0) {
  485. X        /* connection broken */
  486. X        gh->master_flag &= ~M_EXPIRE;    /* remains blocked */
  487. X        db_write_group(gh);
  488. X        break;
  489. X    }
  490. X#endif
  491. X    if (temp > 0) {
  492. X        col_article_count += temp;
  493. X        col_group_count++;
  494. X    }
  495. X
  496. X     unblock_group:
  497. X    if (temp > 0 || (gh->master_flag & M_BLOCKED)) {
  498. X        gh->master_flag &= ~(M_EXPIRE | M_BLOCKED);
  499. X        db_write_group(gh);
  500. X    }
  501. X    }
  502. X
  503. X    if (col_article_count > 0)
  504. X    log_entry('C', "Collect: %ld art, %d gr, %ld s",
  505. X          col_article_count, col_group_count,
  506. X          cur_time() - start_time);
  507. X
  508. X    return temp >= 0;
  509. X}
  510. END_OF_FILE
  511.   if test 11227 -ne `wc -c <'collect.c'`; then
  512.     echo shar: \"'collect.c'\" unpacked with wrong size!
  513.   fi
  514.   # end of 'collect.c'
  515. fi
  516. if test -f 'doc/NEWS-6.4' -a "${1}" != "-c" ; then 
  517.   echo shar: Will not clobber existing file \"'doc/NEWS-6.4'\"
  518. else
  519.   echo shar: Extracting \"'doc/NEWS-6.4'\" \(12220 characters\)
  520.   sed "s/^X//" >'doc/NEWS-6.4' <<'END_OF_FILE'
  521. XNew features in release 6.4 (compared to release 6.3.10):
  522. X---------------------------------------------------------
  523. X
  524. XIncompatible changes:
  525. X    Regular expressions in kill file are now CASE INSENSITIVE by default.
  526. X    - must use '/=' instead of '/' to get 6.3 behaviour.
  527. X
  528. XMajor improvements:
  529. X    Uses standard .newsrc
  530. X    Individual articles can be left unread between invocations.
  531. X    Even individual digest sub-articles can remain unread!!!
  532. X    Articles can also remain "selected" between invocations.
  533. X    New faster expiration in database
  534. X    Unsubscribed groups can be omitted from .newsrc.
  535. X    More flexible and configureable installation.
  536. X    Locking to avoid simultaneous use of nn.
  537. X    Global database locking.
  538. X    Optional accounting, quota, and authorization possibilities.
  539. X    Presentation sequence can now be (partially) based on .newsrc
  540. X    Nnmaster can automatically archive all new articles in selected groups.
  541. X    Related groups can be merged into one group when shown to the user.
  542. X    Menus are now sorted in "subject age" order.
  543. X    Map command can now include definition of anonymous macroes.
  544. X    Auto kill/select possibilities significantly expanded.
  545. X
  546. X
  547. XLevel of program changes (from user's point of view):
  548. X *** => new program, ** => major changes/rewrite, * => minor changes
  549. X
  550. X **    nn(1)        The news reader program
  551. X ***    nnacct(1m)    Accounting, quota, and access management
  552. X *    nnadmin(1m)    The administration program (link to nn)
  553. X *    nncheck(1)    Check for unread articles (link to nn)
  554. X **    nngoback(1)    Mark older articles as unread (link to nn)
  555. X ***    nngrab(1)    Faster keyword search
  556. X **    nngrep(1)    Grep for news groups (link to nn)
  557. X **    nnmaster(8)    Database manager
  558. X ***    nnpost(1)    Standalone posting program (link to nn).
  559. X ***    nnspew(8)    Subject list maintenance
  560. X **    nntidy(1)    Cleans up the rc file (link to nn)
  561. X ***    nnstats(1m)    Collection and expiration statistics
  562. X *    nnusage(1)    Show usage statistics
  563. X
  564. X
  565. XChanges in standard key mappings:
  566. X---------------------------------
  567. X
  568. Xselection mode:
  569. X CR -> continue-no-mark        (IMPORTANT!)
  570. X J  -> junk-articles
  571. X L  -> leave-next
  572. X "  -> layout
  573. X
  574. Xreading mode:
  575. X L  -> leave-next
  576. X
  577. X
  578. XNew key commands:
  579. X-----------------
  580. X
  581. Xcontinue-no-mark    (CR)
  582. Xjunk-articles        (J)
  583. Xleave-next        (L)
  584. X
  585. X
  586. XNew control structures in init file
  587. X-----------------------------------
  588. X
  589. Xon host ... end        Execute only on specified hosts
  590. Xon term ... end        Execute only on specified terminals
  591. Xon slow ... end        Execute only at slow speed
  592. Xon fast ... end        Execute only at higher speeds (>2400)
  593. Xsave-files ... end    Specify default save files for groups
  594. X            without messing up the sequence.
  595. X
  596. X:bug            send a bug report
  597. X:cost            show current accounting figures
  598. X:local VARIABLE [VALUE]    make VARIABLE local to current group [and set to VALUE]
  599. X:rmail            read incoming mail (no update)
  600. X:show rc [GROUP]    show (current) GROUPS .newsrc entry
  601. X
  602. XNew menu sorting methods
  603. X------------------------
  604. X
  605. X:sort sender
  606. X:sort lexical
  607. X:sort subject  (will order subjects according to age of first article)
  608. X
  609. X
  610. XNew variables
  611. X-------------
  612. X
  613. Xappend-signature-mail    Explicitly append .signature to outgoing mail
  614. Xappend-signature-post    Explicitly append .signature to posted articles
  615. Xattributes        Article attribute symbols
  616. Xauto-junk-seen        Automatically mark seen articles read
  617. Xauto-preview-mode    Enter preview mode when selecting an article on menu
  618. Xbackup    (new semantics)    Keep backup of rc file (-B)
  619. Xbackup-suffix STR    String to append to backup file names (.bak)
  620. Xbug-report-address    Mail address for the :bug command
  621. Xcase-fold-search    String and pattern matching is case independent (! -i)
  622. Xcollapse-subject    Offset at which long subjects are compressed
  623. Xconfirm-auto-quit    User must confirm quit after reading last group
  624. Xconfirm-create        User must confirm creation of new files
  625. Xconfirm-entry        User must confirm entry to groups
  626. Xconfirm-entry-limit N    - confirm only for groups with more than N unread art.
  627. Xconfirm-junk-seen    Ask for confirmation before marking seen articles read
  628. Xcross-filter-seq    Show cross posted articles in first group in sequence
  629. Xdata-bits N        Screen output is 7 or 8 bits
  630. Xdecode-skip-prefix N    Automatically unshar uuencoded articles if N>0
  631. Xedit-patch-command    Allow user to edit command used by :patch before exec
  632. Xedit-print-command    Allow user to edit command used by :print before exec
  633. Xedit-unshar-command    Allow user to edit command used by :unshar before exec
  634. Xedit-response-check    Don't send articles if they are not edited.
  635. Xeditor CMD        Use speficied editor instead of $EDITOR
  636. Xentry-report-limit N    Give entry report for groups with >N unread articles
  637. Xexpired-message-delay N    Wait for N seconds after telling article is expired.
  638. Xflush-typeahead        Flush typeahead before reading each command
  639. Xinclude-full-header    M command includes full header in mailed articles.
  640. Xkeep-unsubscribed    Keep unsubscribed groups in .newsrc
  641. Xmailer CMD        Use CMD to send outgoing mail
  642. Xmailer-pipe-input    'mailer' reads standard input/takes file argument
  643. Xmmdf-format        Folders are written in MMDF format
  644. Xnew-group-action N    Specifies how NEW groups are handles -- see :man
  645. Xnewsrc FILE        Specify alternative .newsrc file (new semantics)
  646. Xnntp-cache-dir DIR    Alternative directory for nntp cache files
  647. Xnntp-cache-size N    Max number of different files in cache.
  648. Xorig-to-include-mask N    Specifies which header fields are placed in Orig-To:
  649. Xpreview-continuation N    Specifies what to do after preview of one article
  650. Xpreview-mark-read    Previewing an article marks it read
  651. Xquery-signature        Ask for confirmation before appending .signature
  652. Xquick-count        Use quick method to count unread articles in .newsrc
  653. Xre-layout N        Presentation of Re: prefixes on menu subjects
  654. Xrepeat-group-query    Cause 'nn -g' to repeat group query (-r)
  655. Xreport-cost        Report cost of session on exit
  656. Xresponse-check-pause N    Wait N seconds after mailing/posting for error check
  657. Xresponse-default-answer STR    Default answer to action prompt
  658. Xretain-seen-status    Retain articles' seen status between invocations
  659. Xretry-on-error N    Retry N times if open of article fails
  660. Xsave-counter-offset    First value of save counter
  661. Xscroll-clear-page    Scrolling clears page before drawing next page
  662. Xselect-on-sender    Should = command on menu match on sender or subject
  663. Xselect-leave-next    Ask to mark leave-next articles selected on entry
  664. Xslow-mode        Minimize screen output
  665. Xslow-speed SPEED    'on slow' clause is true for this and lower speeds
  666. Xsort-mode N        Default sort mode for menus and :sort command
  667. Xspell-checker CMD    Spelling checker for edited messages (one arg)
  668. Xsubject-match-limit N    Treat subjects matching in N characters as identical
  669. Xsubject-match-offset N    Skip N characters of subjects before comparison
  670. Xsubject-match-parts    Treat subjects matching upto first digit as idential
  671. Xsuggest-default-save    Show default save file name on prompt line.
  672. Xtidy-newsrc        Automatically remove garbage from .newsrc
  673. Xupdate-frequency N    Write .newsrc for every N groups
  674. Xuse-selections        Use select file
  675. Xvisible-bell        Use visible bell if defined in termcap/terminfo
  676. Xwrap-header-margin    Fold long header lines over multiple lines
  677. X
  678. X
  679. XNew options:
  680. X------------
  681. X
  682. Xnnmaster: -G -l [lock message] -i -H -k -O -X
  683. X      -I [limit] -D [level] -Q   [[!]group]...
  684. Xnntidy:   -N -Q -v -a -c -i -r -s -u
  685. Xnngrep:   -a -n -p -r -s -u -l
  686. Xnncheck:  -c [groups]...
  687. Xnngoback: -v -i [groups]...
  688. Xnn:      -Ifiles -nsender -i
  689. X
  690. Xnnadmin changes
  691. X---------------
  692. X
  693. XE)xpire and I)nitialize commands now requires confirmation also when
  694. Xcalled from command line:
  695. X    nnadmin =EYW    -- request expire (from cron)
  696. X    nnadmin IY    -- request rebuild
  697. X
  698. XZ)ap in GROUP menu -- will call rmgroup to remove group.
  699. XV)alidation can now be run from nn's :admin command.
  700. XD)ump entry on master menu.
  701. X! - will fork subshell on all menus.
  702. X
  703. X
  704. XOther changes (highlights):
  705. X---------------------------
  706. X
  707. XNOTICE: nn no longer relies on the `min' field in the active file to
  708. X    detect expire. So there is no need to run the `upact' program
  709. X    with Cnews anymore.
  710. X
  711. Xnntidy, nngoback and nngrep are now integrated into nn giving them a
  712. Xmuch greater flexibility, e.g. you can go back on individual groups or
  713. Xhierarchies (interactively).
  714. X
  715. Xnnmaster can now ignore and optionally remove badly formed and
  716. Xout-dated articles in the news spool directory (not with NNTP).
  717. XThis can give more accurate numbers of unread articles, and also
  718. Xsmaller databases.
  719. X
  720. XIndividual groups and group hierarchies can now be permanently
  721. Xexcluded from the database, and per-group flags can be permanantly set
  722. Xin the GROUPS file. Groups can be automatically archived and archive
  723. Xis directly available from nn. Some possibilities are:
  724. X
  725. X    R    recollect all articles on every scan
  726. X    X    ignore group
  727. X    D    always try to split articles as digests
  728. X    N    never attempt to digest articles
  729. X    >file    append all new articles to file
  730. X
  731. X'*' part counter can now be specified anywhere in save file names.
  732. XSeveral roblems with `$N' has been fixed.
  733. X
  734. XDefault save file names are now expanded ($L/$F/$G) when shown.
  735. X
  736. XRC, RC:nnn, and RC:string forms can now be specified in the
  737. Xpresentation sequence to use all or part of .newsrc as the
  738. Xgroup order information when building presentation sequence.
  739. X
  740. XThe kill file can now contain entries which "trigger" on matching more
  741. Xthan one field or value, and it may also contain "kill unless" entries.
  742. XFor example, to kill all articles NOT from ME on subject "XY.*Z:" :
  743. X    group:~n=&s/:ME:XY.*Z\:
  744. X(these complex entries must be entered manually into the kill file).
  745. X
  746. XKill entries can work for a set of groups specified with a regular
  747. Xexpression, e.g.    /^news\.*:+n=:Kim F. Storm
  748. X
  749. XTimezone is now considered when sorting articles on date.
  750. X
  751. XSingle character arrow keys are no longer recognized as arrow keys if
  752. Xthey send the same code as "erase" "kill" "interrupt" CR or NL!!!
  753. X
  754. XNow parses "n", "x", and "=group" codes in the active file and handles
  755. Xgroups accordingly.
  756. X
  757. XUnsubscribed groups can now be omitted from .newsrc provided
  758. Xnew-group-action is set appropriately.  It uses per-group creation
  759. Xtime stamps saved either in a .nn/LAST file or an rn compatible
  760. X.rnlast file.
  761. X
  762. Xnnmaster will now dynamically expand the MASTER file, and thus never
  763. Xrun out of "free group slots".
  764. X
  765. X"q" and "Q" can now be used in addition to ^G and "interrupt" to
  766. Xbreak out of multi-page listings (hit any key to continue).
  767. X
  768. Xnn -a0 will now allow you to (U)nsubscribe to a group and (r)ead a
  769. Xgroup directly.  It also accepts a (q)uit answer.
  770. X
  771. XReturn value when saving through a pipe is now checked and an error
  772. Xmessage is given if the command failed.
  773. X
  774. XMultiple, alternative init files can now be specified to nn via the -I
  775. Xoption:
  776. X    nn -Ia,,b    First read a, then global init file, then b.
  777. X    nn -I,init    This is the default (read global, then local file)
  778. X
  779. X"on term" can now match several terminal types, e.g. "on term t1 t2 t9"
  780. X
  781. XG command now acts "reasonnable" on empty reply to the "number of
  782. X(extra) articles" prompt:
  783. X    If goto another group with unread articles => j
  784. X    If goto another group without unread articles => a
  785. X    If goto same group with more unread articles => u
  786. X    If goto same group without more unread articles => a
  787. X
  788. XThe G command can now search on sender as well as subject (and both).
  789. X
  790. XCross postings are now eliminated according to the presentation
  791. Xsequence rather than the Newsgroups: line by default.  Here is what
  792. XWayne Davison has said about the new method:
  793. X
  794. X    Now that I have been using "tn"s article selector and see the same
  795. X    subjects appear in a second group, I agree with you totally that
  796. X    your new method of handling cross-posted articles is the right way
  797. X    to go.  It gets especially annoying when I have marked a
  798. X    cross-posted article as unread in one group and encounter it in a
  799. X    second group -- I must remember to mark it unread again or it will
  800. X    be marked as read in both groups.  Just thought you might like to
  801. X    know.
  802. X
  803. X
  804. XFour new "selectors" in group sequence.  Neither of these include
  805. Xanything directly in the sequence, but they will EXCLUDE groups from
  806. Xthe sequence:
  807. X    !:X groups    excludes groups not in .newsrc, e.g. "!:X alt*"
  808. X            will exclude all "alt" groups not found in .newsrc.
  809. X    !:O groups    exclude groups unless they are new, e.g.
  810. X            "!:O bionet*" will ignore OLD bionet groups even
  811. X            when they occur in .newsrc.
  812. X    !:U groups    exclude unsubscribed groups.
  813. X    !:N groups    exclude new groups.
  814. X
  815. X
  816. X$(VAR) is now expanded in file names (VAR is an environment variable).
  817. X
  818. XAnd lots more if you upgrade from 6.3.0!!!
  819. END_OF_FILE
  820.   if test 12220 -ne `wc -c <'doc/NEWS-6.4'`; then
  821.     echo shar: \"'doc/NEWS-6.4'\" unpacked with wrong size!
  822.   fi
  823.   # end of 'doc/NEWS-6.4'
  824. fi
  825. if test -f 'doc/NNTP' -a "${1}" != "-c" ; then 
  826.   echo shar: Will not clobber existing file \"'doc/NNTP'\"
  827. else
  828.   echo shar: Extracting \"'doc/NNTP'\" \(12793 characters\)
  829.   sed "s/^X//" >'doc/NNTP' <<'END_OF_FILE'
  830. X                 NNTP SUPPORT
  831. X                 ------------
  832. X
  833. XThis file describes the NNTP support available in nn release 6.4.  The
  834. XNNTP support was implemented by Rene' Seindal, seindal@diku.dk.
  835. X
  836. X
  837. X                PREREQUISITES
  838. X                -------------
  839. X
  840. XFirst of all, you need read-access to an NNTP-server, and if you want
  841. Xto post, the server must allow that.
  842. X
  843. XIf you have news on one of your systems, and want to run an NNTP
  844. Xserver on that system to feed other local systems, you need to get and
  845. Xinstall the nntp-1.5 distribution with at least patches 1-3 (I think
  846. Xpatch 8 is the latest).  It is available from several ftp-sites in the
  847. XUSA.  It is also available on freja.diku.dk (ip 129.142.96.1).
  848. X
  849. XHowever, just to run nn on you local system with or without NNTP, you
  850. Xdon't need anything besides the nn 6.4 distribution!!
  851. X
  852. XThe necessary modules to access a remote NNTP server is an integrated
  853. Xpart of nn, so if you specify to use NNTP, the necessary code is
  854. Xautomatically included.
  855. X
  856. XA recent version of the `mini-inews' program which is required to post
  857. Xarticles via an NNTP server is also included for your convenience.
  858. XSee the INEWS section below.
  859. X
  860. X                 HOW IT WORKS
  861. X                 ------------
  862. X
  863. XNNTP is supported both in nn and nnmaster.  When NNTP is used, the
  864. Xdatabase with the header information used by nn is still maintained on
  865. Xthe local system (because NNTP does not know about the nn database
  866. X(yet?)).
  867. X
  868. XWhen the master is set up to use NNTP, it will connect to the NNTP-
  869. Xserver in each iteration of the collection (the interval set with -r),
  870. Xget a copy of the active file, and incorporate the new articles into the
  871. Xdatabase.  To do this, the master will temporarily transfer one article
  872. Xat a time from the NNTP-server to the local system.
  873. X
  874. XWhen the articles are read with nn, it will use the local database to
  875. Xpresent the menus, and fetch the articles from the NNTP-server as they
  876. Xare requested by the user.  It will connect to the NNTP server the first
  877. Xtime it is necessary to fetch an article.
  878. X
  879. XNeither nnmaster, nor nn will use NNTP if they run on the NNTP-server
  880. Xitself (they will directly access the news files).
  881. X
  882. XBoth nn and nnmaster access the server in reading mode.  The master and
  883. Xall client MUST use the same server at all times, since the local
  884. Xdatabase contains article numbers, that are only unique for each
  885. XNNTP-server.
  886. X
  887. X
  888. X             SHARING THE DATABASE
  889. X             --------------------
  890. X
  891. XYou must also decide whether you want to share the database between your
  892. Xlocal news clients, and how you are going to do it.
  893. X
  894. XThe database will take up some disk space, normally about 1Mb per 10.000
  895. Xarticles.  There are several ways to manage this space.
  896. X
  897. XThis simplest solution, is to let each client run it own master, i.e.,
  898. Xhave its own database.  This means, of course, no sharing.
  899. X
  900. XAlternatively, one host can run the master, and distribute the database
  901. Xto the others via e.g., rdist.  This doesn't save disk space, but saves
  902. Xload on the NNTP-server.
  903. X
  904. XLast, the database can be shared with NFS/RFS (see the description of
  905. XNETWORK_DATABASE in the config.h file).
  906. X
  907. XThe possibility of making a `nndb-server' stands open.  It could be
  908. Xrealized either as a separate server, running under inetd, or it could
  909. Xbe incorporated into nntpd.  It has not been implemented, but might be
  910. Xpart of a future release (any volunteers?).
  911. X
  912. X
  913. X                CONFIGURATION
  914. X                -------------
  915. X
  916. XTo use NNTP in nn, you must edit the relevant parts of config.h:
  917. X
  918. XNNTP
  919. X    You enable the use of NNTP by defining the macro NNTP.
  920. X
  921. XNNTP_SERVER
  922. X    Both the master and the clients will look up their NNTP-server
  923. X    in the file given by the macro NNTP_SERVER.  If the name is not
  924. X    an absolute path name, it is taken to be relative to
  925. X    LIB_DIRECTORY.
  926. X
  927. X    The format of the file is compatible with the one used in
  928. X    clientlib.c in the nntp-1.5 distribution, i.e., the first
  929. X    non-blank line, not starting with '#' is taken to be the name of
  930. X    the NNTP-server.  This file MUST be present, and must contain a
  931. X    valid host name.
  932. X
  933. XNNTP_POST
  934. X    If you use the NNTP based inews (part on the NNTP distribution)
  935. X    and you have hosts that are not allowed to post to the NNTP
  936. X    server, you should defined this.  It will make nn check at
  937. X    connect time whether the NNTP server allows postings, and reject
  938. X    all attempts to post, if the server disallows posting.  If you
  939. X    do not define this, users will be allowed to post by nn, but the
  940. X    posting will eventually fail.
  941. X
  942. X    Again, this parameter is only relevant, if you use the NNTP
  943. X    based inews, and have hosts that are not allowed to post.
  944. X
  945. XNNTP_MINI_INEWS_HEADER
  946. X    According to RFC 977, the mini-inews that comes with nntp
  947. X    requires that the articles it receives contain a complete
  948. X    header including Message-ID, Date, and Path fields (which the
  949. X    normal inews generates itself).  I consider this to be a bug
  950. X    in the RFC, and maybe some (future?) versions of mini-inews
  951. X    will provide these fields.  However, if you use mini-inews for
  952. X    postings and your version of mini-inews does not generate
  953. X    these headers, you should define NNTP_MINI_INEWS_HEADER in
  954. X    config.h.  Notice that the Message-ID and Path may be less
  955. X    than perfect (but the Message-ID should be unique)!
  956. X
  957. X
  958. XNEWS_LIB_DIRECTORY & INEWS
  959. X    If either is defined, they specify the destination of the
  960. X    mini-inews program when installed below with INEWS being used
  961. X    if both are defined.  If neither is defined, it will be
  962. X    installed in /usr/lib/news/inews.
  963. X
  964. X    
  965. X        
  966. X                TUNING
  967. X                ------
  968. X
  969. XBoth the server and each client maintains a cache of recently accessed
  970. Xarticles, to minimize communication with the server (mainly to avoid
  971. Xfetching large digests continuously).  The master needs the cache when
  972. Xit splits digests, and the clients need it, because nn has a tendency to
  973. Xreopen the articles several times.
  974. X
  975. XThe master's cache is kept in LIB_DIRECTORY, and each client's cache are
  976. Xkept in the users .nn directory.  The constant NNTPCACHE (defined in
  977. Xnntp.c but can be redefined in config.h) defines the size of the cache,
  978. Xwhose optimal size depends on the amount of news kept on line on the
  979. XNNTP-server.  Values of 5-10 gives reasonable results.  The effect is
  980. Xmost striking when reading digested news.
  981. X
  982. XThe location and size of the cache can also be changed on a per-user
  983. Xbasis via the related nntp- variables (see nn.1).
  984. X
  985. X
  986. X                 INSTALLATION
  987. X                 ------------
  988. X
  989. XMaking and installing nn using NNTP does not differ from a non-NNTP nn
  990. Xinstallation, except for the differences in the configuration and the
  991. Xneed to specify the NNTP server in the NNTP_SERVER file.
  992. X
  993. XNotice however, that the NNTP_SERVER file must be properly initialized
  994. Xbefore doing the 'make initdb'.
  995. X
  996. XIf something goes wrong in the initialization of the database, you will
  997. Xhave to run 'nnmaster -I' again by hand.
  998. X
  999. X
  1000. X                INEWS
  1001. X                -----
  1002. X
  1003. XIf you want to post news via the NNTP server, you will need to run a
  1004. Xprogram named `(mini-)inews' which is included in the normal NNTP
  1005. Xdistribution.  However, since this is the only part of the NNTP you
  1006. Xneed to run nn, a recent version (1.5.7) of the mini-inews program is
  1007. Xincluded with nn in the inews/ directory.
  1008. X
  1009. XIf you already have installed and maintain mini-inews on your system,
  1010. Xyou should not use the version that comes with nn - it would just be
  1011. Xextra unnecessary work.
  1012. X
  1013. XHowever, if you don't run mini-inews already, using the version that
  1014. Xcomes with nn will be somewhat simpler to configure, because it takes
  1015. Xadvantage of the definitions you have already made for nn in config.h.
  1016. X
  1017. XThanks to Steve Simmons who contributed the simplified inews
  1018. Xconfiguration (which I took the freedom to simplify even further).
  1019. X
  1020. XTo configure and install mini-inews, all you should need to do is
  1021. X(everything must be done with inews/ as current working directory):
  1022. X
  1023. X    $ cd inews
  1024. X    $ edit conf.h    -- modify as described in the file
  1025. X    $ make
  1026. X
  1027. XIf things work, type:
  1028. X
  1029. X    $ su
  1030. X    # make install
  1031. X
  1032. XAs far as I know, NNTP_MINI_INEWS_HEADER needs to be defined in
  1033. Xnn's config.h for nn to work with this mini-inews version.
  1034. X
  1035. XSee the files inews/README.NN and inews/README for further information.
  1036. X
  1037. X
  1038. X                ERROR HANDLING
  1039. X                --------------
  1040. X
  1041. XThe handling of errors have been improved since the initial release.
  1042. X
  1043. XThe master will handle most errors by closing the connection, and
  1044. Xreturning to the main loop.  All errors in the master are logged, with
  1045. Xa code of `N,' so they can be inspected with the `n' command in
  1046. Xnnadmin's Log menu.
  1047. X
  1048. XA few errors are considere fatal. If any of these occur operation will
  1049. Xbe discontinued.  These errors are such as failure to find the NNTP
  1050. Xserver, failure to find the NNTP service, and responses from the NNTP
  1051. Xserver in the 500 range (ill-formed requests, access denied, ...)
  1052. X
  1053. XNNTP server timeouts are handled specially.  If the NNTP server times
  1054. Xout, both nn and the master will attempt to restart it (by connecting
  1055. Xagain).  This shouldn't happen in the master (which won't leave sockets
  1056. Xidle for that long), but it can easily happen in nn, if it is left
  1057. Xsuspended for too long.  If the server responds with code 400 (Service
  1058. Xdiscontinued), a reconnect is also tried.
  1059. X
  1060. X
  1061. X                   PROBLEMS
  1062. X                   --------
  1063. X
  1064. XI am not certain what should happen if the server sends back responses
  1065. Xin the 1xx range.  I do not know whether a NNTP server is allowed to
  1066. Xreturn one of these responses on its own initiative.  If it is, nn
  1067. Xshould probably ignore (or display) the messages.  Currently, nothing is
  1068. Xdone to treat these responses in any way.
  1069. X
  1070. XI have seen a strange thing happen to the master, which I have not been
  1071. Xable to reproduce.  The master ran on a Sun-4 running SunOS 4.0, and the
  1072. XNNTP server was a VAX 785 running MORE/bsd.  The NNTP software was
  1073. Xversion 1.5.3.  The master was stuck in a read from the NNTP server.  A
  1074. Xnetstat on the Sun show an established connection to nntpd on the Vax,
  1075. Xbut a netstat on the Vasx did not show any NNTP connections.  There was
  1076. Xno nntpd running, and no messages on the console indicating any
  1077. Xfailures.
  1078. X
  1079. X[ It is now known that this problem is related to the socket not
  1080. X  having the KEEP ALIVE flag set, but I have not got the necessary
  1081. X  patches to fix it,   ++Kim ]
  1082. X
  1083. X
  1084. XIf you want to debug the nntp connection, you can run the nnmaster
  1085. Xwith the option -D2 (or -D3 which also turns on the normal -D verbose
  1086. Xoutput).  In the nn client, you can turn on the nntp-debug variable in
  1087. Xthe init file.
  1088. X
  1089. XThe debug output from nnmaster will be placed in $TMP/nnmaster.log
  1090. Xwhile the output in the client will appear on the message line.
  1091. X
  1092. X
  1093. X        POSSIBLE EXTENTIONS TO THE NNTP SERVER
  1094. X        --------------------------------------
  1095. X
  1096. XThe new expire method used in release 6.4 is very efficient on local
  1097. Xsystems, because it will just read the spool directories to get a list
  1098. Xof available articles in each group.
  1099. X
  1100. XHowever, with nntp, the only way I know of to get a list of available
  1101. Xarticles in a group with nntp is the XHDR request.  However, this will
  1102. Xopen every article in the group to extract the desired field, but the
  1103. Xonly thing I am interested in is the article number itself.
  1104. X
  1105. XSo I suggest to add a LISTGROUP request to the NNTP server to return
  1106. Xthe equivalent of
  1107. X    ls $GROUPDIR | sed -n '/^[0-9][0-9]*$/p'
  1108. X(in any order - nnmaster will sort the list itself).
  1109. X
  1110. XCurrently nnmaster will test whether this request works before using
  1111. Xthe XHDR request, so no changes to nnmaster will be required to take
  1112. Xadvantage of such a fix.
  1113. X
  1114. X
  1115. XAnother possible performance increase would be if there was a request
  1116. Xto get the current modification time of the ACTIVE file.  This is the
  1117. Xcheck nnmaster will do to see if there might be work to do on a local
  1118. Xsystem, but with NNTP it has to read the active file from the server
  1119. Xand compare it to a local copy to determine whether there is work to
  1120. Xdo.  A simple ACTIVESTAT request returning the active file's age and
  1121. Xsize would fix this.
  1122. X
  1123. XCurrently nnmaster is not prepared to use such a request, but it would
  1124. Xbe easy to add.
  1125. X
  1126. X
  1127. X                 ALTERNATIVES
  1128. X                 ------------
  1129. X
  1130. XAlternative implementations can be conceived, especially in the master.
  1131. XThe master normally collects articles by rereading the active file,
  1132. Xlooking for changed article numbers.  For each group with new articles,
  1133. Xit reads the new articles and adds them to the database.  This scheme
  1134. Xhas been kept in the NNTP-based master, to keep the changes at a
  1135. Xminimum.
  1136. X
  1137. XAn alternative solution could be to use NEWNEWS to get a list of new
  1138. Xarticles since last collect, and fetch each article in sequence.  The
  1139. Xnewsgroups and article numbers within each group could then be found in
  1140. Xthe Xref: field.  This would probably improve efficiency, since the
  1141. Xmaster would then generate fewer failing requests (for non-existent
  1142. Xarticles), and it would only read cross-posted articles once.  This
  1143. Xsolution would, however, require some surgery on the current structure
  1144. Xof the masters main loop.
  1145. X
  1146. XSuggestions and improvements are very much welcome.  Send your ideas or
  1147. Xcontributions to nn-bugs@dkuug.dk.
  1148. END_OF_FILE
  1149.   if test 12793 -ne `wc -c <'doc/NNTP'`; then
  1150.     echo shar: \"'doc/NNTP'\" unpacked with wrong size!
  1151.   fi
  1152.   # end of 'doc/NNTP'
  1153. fi
  1154. if test -f 'inews/clientlib.c' -a "${1}" != "-c" ; then 
  1155.   echo shar: Will not clobber existing file \"'inews/clientlib.c'\"
  1156. else
  1157.   echo shar: Extracting \"'inews/clientlib.c'\" \(11231 characters\)
  1158.   sed "s/^X//" >'inews/clientlib.c' <<'END_OF_FILE'
  1159. X#ifndef lint
  1160. Xstatic char    *sccsid = "@(#)clientlib.c    1.11    (Berkeley) 10/27/89";
  1161. X#endif
  1162. X
  1163. X/*
  1164. X * NNTP client routines.
  1165. X */
  1166. X
  1167. X/*
  1168. X * Include configuration parameters only if we're made in the nntp tree.
  1169. X */
  1170. X
  1171. X#ifdef FOR_NN
  1172. X#include "conf.h"
  1173. X#endif
  1174. X
  1175. X#ifdef NNTPSRC
  1176. X#include "../config.h"
  1177. X#endif NNTPSRC
  1178. X
  1179. X#include <stdio.h>
  1180. X#ifndef FOR_NN
  1181. X#include <sys/types.h>
  1182. X#endif
  1183. X#include <sys/socket.h>
  1184. X#include <netinet/in.h>
  1185. X#ifndef EXCELAN
  1186. X# include <netdb.h>
  1187. X#endif not EXCELAN
  1188. X
  1189. X#ifndef FOR_NN
  1190. X#ifdef USG
  1191. X# define    index    strchr
  1192. X#endif USG
  1193. X#endif
  1194. X
  1195. X#ifdef EXCELAN
  1196. X# define    IPPORT_NNTP    119
  1197. X#endif
  1198. X
  1199. X#ifdef DECNET
  1200. X#include <netdnet/dn.h>
  1201. X#include <netdnet/dnetdb.h>
  1202. X#endif DECNET
  1203. X
  1204. X#include "nntp.h"
  1205. X
  1206. XFILE    *ser_rd_fp = NULL;
  1207. XFILE    *ser_wr_fp = NULL;
  1208. X
  1209. X/*
  1210. X * getserverbyfile    Get the name of a server from a named file.
  1211. X *            Handle white space and comments.
  1212. X *            Use NNTPSERVER environment variable if set.
  1213. X *
  1214. X *    Parameters:    "file" is the name of the file to read.
  1215. X *
  1216. X *    Returns:    Pointer to static data area containing the
  1217. X *            first non-ws/comment line in the file.
  1218. X *            NULL on error (or lack of entry in file).
  1219. X *
  1220. X *    Side effects:    None.
  1221. X */
  1222. X
  1223. Xchar *
  1224. Xgetserverbyfile(file)
  1225. Xchar    *file;
  1226. X{
  1227. X    register FILE    *fp;
  1228. X    register char    *cp;
  1229. X    static char    buf[256];
  1230. X    char        *index();
  1231. X    char        *getenv();
  1232. X    char        *strcpy();
  1233. X
  1234. X    if (cp = getenv("NNTPSERVER")) {
  1235. X        (void) strcpy(buf, cp);
  1236. X        return (buf);
  1237. X    }
  1238. X
  1239. X    if (file == NULL)
  1240. X        return (NULL);
  1241. X
  1242. X    fp = fopen(file, "r");
  1243. X    if (fp == NULL)
  1244. X        return (NULL);
  1245. X
  1246. X    while (fgets(buf, sizeof (buf), fp) != NULL) {
  1247. X        if (*buf == '\n' || *buf == '#')
  1248. X            continue;
  1249. X        cp = index(buf, '\n');
  1250. X        if (cp)
  1251. X            *cp = '\0';
  1252. X        (void) fclose(fp);
  1253. X        return (buf);
  1254. X    }
  1255. X
  1256. X    (void) fclose(fp);
  1257. X    return (NULL);             /* No entry */
  1258. X}
  1259. X
  1260. X
  1261. X/*
  1262. X * server_init  Get a connection to the remote news server.
  1263. X *
  1264. X *    Parameters:    "machine" is the machine to connect to.
  1265. X *
  1266. X *    Returns:    -1 on error
  1267. X *            server's initial response code on success.
  1268. X *
  1269. X *    Side effects:    Connects to server.
  1270. X *            "ser_rd_fp" and "ser_wr_fp" are fp's
  1271. X *            for reading and writing to server.
  1272. X */
  1273. X
  1274. Xserver_init(machine)
  1275. Xchar    *machine;
  1276. X{
  1277. X    int    sockt_rd, sockt_wr;
  1278. X    char    line[256];
  1279. X    char    *index();
  1280. X#ifdef DECNET
  1281. X    char    *cp;
  1282. X
  1283. X    cp = index(machine, ':');
  1284. X
  1285. X    if (cp && cp[1] == ':') {
  1286. X        *cp = '\0';
  1287. X        sockt_rd = get_dnet_socket(machine);
  1288. X    } else
  1289. X        sockt_rd = get_tcp_socket(machine);
  1290. X#else
  1291. X    sockt_rd = get_tcp_socket(machine);
  1292. X#endif
  1293. X
  1294. X    if (sockt_rd < 0)
  1295. X        return (-1);
  1296. X
  1297. X    /*
  1298. X     * Now we'll make file pointers (i.e., buffered I/O) out of
  1299. X     * the socket file descriptor.  Note that we can't just
  1300. X     * open a fp for reading and writing -- we have to open
  1301. X     * up two separate fp's, one for reading, one for writing.
  1302. X     */
  1303. X
  1304. X    if ((ser_rd_fp = fdopen(sockt_rd, "r")) == NULL) {
  1305. X        perror("server_init: fdopen #1");
  1306. X        return (-1);
  1307. X    }
  1308. X
  1309. X    sockt_wr = dup(sockt_rd);
  1310. X    if ((ser_wr_fp = fdopen(sockt_wr, "w")) == NULL) {
  1311. X        perror("server_init: fdopen #2");
  1312. X        ser_rd_fp = NULL;        /* from above */
  1313. X        return (-1);
  1314. X    }
  1315. X
  1316. X    /* Now get the server's signon message */
  1317. X
  1318. X    (void) get_server(line, sizeof(line));
  1319. X    return (atoi(line));
  1320. X}
  1321. X
  1322. X
  1323. X/*
  1324. X * get_tcp_socket -- get us a socket connected to the news server.
  1325. X *
  1326. X *    Parameters:    "machine" is the machine the server is running on.
  1327. X *
  1328. X *    Returns:    Socket connected to the news server if
  1329. X *            all is ok, else -1 on error.
  1330. X *
  1331. X *    Side effects:    Connects to server.
  1332. X *
  1333. X *    Errors:        Printed via perror.
  1334. X */
  1335. X
  1336. Xget_tcp_socket(machine)
  1337. Xchar    *machine;
  1338. X{
  1339. X    int    s;
  1340. X    struct    sockaddr_in sin;
  1341. X#ifndef EXCELAN
  1342. X    struct    servent *getservbyname(), *sp;
  1343. X    struct    hostent *gethostbyname(), *hp;
  1344. X#ifdef h_addr
  1345. X    int    x = 0;
  1346. X    register char **cp;
  1347. X#endif h_addr
  1348. X
  1349. X    if ((sp = getservbyname("nntp", "tcp")) ==  NULL) {
  1350. X        fprintf(stderr, "nntp/tcp: Unknown service.\n");
  1351. X        return (-1);
  1352. X    }
  1353. X
  1354. X       /*
  1355. X        * Name resolution doesn't quite go as far as it should.  Take things
  1356. X        * one stage further to allow nnn.nnn.nnn.nnn addresses if all else
  1357. X        * fails.
  1358. X        */
  1359. X       if( (hp = gethostbyname( machine ) ) == NULL ) {
  1360. X               unsigned long inet_addr();
  1361. X               static struct hostent def;
  1362. X               static struct in_addr defaddr;
  1363. X               static char *alist[1];
  1364. X               static char namebuf[ 256 ];
  1365. X               defaddr.s_addr = inet_addr( machine );
  1366. X               if( defaddr.s_addr != -1 ) {
  1367. X                       strcpy( namebuf, machine );
  1368. X                       def.h_name = namebuf;
  1369. X#ifdef h_addr
  1370. X                       def.h_addr_list = alist;
  1371. X#endif
  1372. X                       def.h_addr = (char *)&defaddr;
  1373. X                       def.h_length = sizeof( struct in_addr );
  1374. X                       def.h_addrtype = AF_INET;
  1375. X                       def.h_aliases = 0;
  1376. X                       hp = &def;
  1377. X               }
  1378. X       }
  1379. X       if (hp == NULL) {
  1380. X        fprintf(stderr, "%s: Unknown host.\n", machine);
  1381. X        return (-1);
  1382. X    }
  1383. X
  1384. X    bzero((char *) &sin, sizeof(sin));
  1385. X    sin.sin_family = hp->h_addrtype;
  1386. X    sin.sin_port = sp->s_port;
  1387. X#else EXCELAN
  1388. X    bzero((char *) &sin, sizeof(sin));
  1389. X    sin.sin_family = AF_INET;
  1390. X    sin.sin_port = htons(IPPORT_NNTP);
  1391. X#endif EXCELAN
  1392. X
  1393. X    /*
  1394. X     * The following is kinda gross.  The name server under 4.3
  1395. X     * returns a list of addresses, each of which should be tried
  1396. X     * in turn if the previous one fails.  However, 4.2 hostent
  1397. X     * structure doesn't have this list of addresses.
  1398. X     * Under 4.3, h_addr is a #define to h_addr_list[0].
  1399. X     * We use this to figure out whether to include the NS specific
  1400. X     * code...
  1401. X     */
  1402. X
  1403. X#ifdef    h_addr
  1404. X
  1405. X    /* get a socket and initiate connection -- use multiple addresses */
  1406. X
  1407. X    for (cp = hp->h_addr_list; cp && *cp; cp++) {
  1408. X        s = socket(hp->h_addrtype, SOCK_STREAM, 0);
  1409. X        if (s < 0) {
  1410. X            perror("socket");
  1411. X            return (-1);
  1412. X        }
  1413. X            bcopy(*cp, (char *)&sin.sin_addr, hp->h_length);
  1414. X
  1415. X        if (x < 0)
  1416. X            fprintf(stderr, "trying %s\n", inet_ntoa(sin.sin_addr));
  1417. X        x = connect(s, (struct sockaddr *)&sin, sizeof (sin));
  1418. X        if (x == 0)
  1419. X            break;
  1420. X                fprintf(stderr, "connection to %s: ", inet_ntoa(sin.sin_addr));
  1421. X        perror("");
  1422. X        (void) close(s);
  1423. X    }
  1424. X    if (x < 0) {
  1425. X        fprintf(stderr, "giving up...\n");
  1426. X        return (-1);
  1427. X    }
  1428. X#else    /* no name server */
  1429. X#ifdef EXCELAN
  1430. X    if ((s = rresvport(SO_KEEPALIVE)) < 0)
  1431. X    {
  1432. X        /* Get the socket */
  1433. X        perror("socket");
  1434. X        return (-1);
  1435. X    }
  1436. X    /* set up addr for the connect */
  1437. X    sin.sin_addr.s_addr = rhost(machine);
  1438. X    if (sin.sin_addr.s_addr < 0){
  1439. X        fprintf(stderr, "%s: Unknown host.\n", machine);
  1440. X        return (-1);
  1441. X    }
  1442. X    /* And then connect */
  1443. X
  1444. X    if (connect(s, &sin) < 0) {
  1445. X        perror("connect");
  1446. X        (void) close(s);
  1447. X        return (-1);
  1448. X    }
  1449. X#else not EXCELAN
  1450. X    if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
  1451. X        perror("socket");
  1452. X        return (-1);
  1453. X    }
  1454. X
  1455. X    /* And then connect */
  1456. X
  1457. X    bcopy(hp->h_addr, (char *) &sin.sin_addr, hp->h_length);
  1458. X    if (connect(s, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
  1459. X        perror("connect");
  1460. X        (void) close(s);
  1461. X        return (-1);
  1462. X    }
  1463. X
  1464. X#endif not EXCELAN
  1465. X#endif
  1466. X
  1467. X    return (s);
  1468. X}
  1469. X
  1470. X#ifdef DECNET
  1471. X/*
  1472. X * get_dnet_socket -- get us a socket connected to the news server.
  1473. X *
  1474. X *    Parameters:    "machine" is the machine the server is running on.
  1475. X *
  1476. X *    Returns:    Socket connected to the news server if
  1477. X *            all is ok, else -1 on error.
  1478. X *
  1479. X *    Side effects:    Connects to server.
  1480. X *
  1481. X *    Errors:        Printed via nerror.
  1482. X */
  1483. X
  1484. Xget_dnet_socket(machine)
  1485. Xchar    *machine;
  1486. X{
  1487. X    int    s, area, node;
  1488. X    struct    sockaddr_dn sdn;
  1489. X    struct    nodeent *getnodebyname(), *np;
  1490. X
  1491. X    bzero((char *) &sdn, sizeof(sdn));
  1492. X
  1493. X    switch (s = sscanf( machine, "%d%*[.]%d", &area, &node )) {
  1494. X        case 1:
  1495. X            node = area;
  1496. X            area = 0;
  1497. X        case 2:
  1498. X            node += area*1024;
  1499. X            sdn.sdn_add.a_len = 2;
  1500. X            sdn.sdn_family = AF_DECnet;
  1501. X            sdn.sdn_add.a_addr[0] = node % 256;
  1502. X            sdn.sdn_add.a_addr[1] = node / 256;
  1503. X            break;
  1504. X        default:
  1505. X            if ((np = getnodebyname(machine)) == NULL) {
  1506. X                fprintf(stderr,
  1507. X                    "%s: Unknown host.\n", machine);
  1508. X                return (-1);
  1509. X            } else {
  1510. X                bcopy(np->n_addr,
  1511. X                    (char *) sdn.sdn_add.a_addr,
  1512. X                    np->n_length);
  1513. X                sdn.sdn_add.a_len = np->n_length;
  1514. X                sdn.sdn_family = np->n_addrtype;
  1515. X            }
  1516. X            break;
  1517. X    }
  1518. X    sdn.sdn_objnum = 0;
  1519. X    sdn.sdn_flags = 0;
  1520. X    sdn.sdn_objnamel = strlen("NNTP");
  1521. X    bcopy("NNTP", &sdn.sdn_objname[0], sdn.sdn_objnamel);
  1522. X
  1523. X    if ((s = socket(AF_DECnet, SOCK_STREAM, 0)) < 0) {
  1524. X        nerror("socket");
  1525. X        return (-1);
  1526. X    }
  1527. X
  1528. X    /* And then connect */
  1529. X
  1530. X    if (connect(s, (struct sockaddr *) &sdn, sizeof(sdn)) < 0) {
  1531. X        nerror("connect");
  1532. X        close(s);
  1533. X        return (-1);
  1534. X    }
  1535. X
  1536. X    return (s);
  1537. X}
  1538. X#endif
  1539. X
  1540. X
  1541. X
  1542. X/*
  1543. X * handle_server_response
  1544. X *
  1545. X *    Print some informative messages based on the server's initial
  1546. X *    response code.  This is here so inews, rn, etc. can share
  1547. X *    the code.
  1548. X *
  1549. X *    Parameters:    "response" is the response code which the
  1550. X *            server sent us, presumably from "server_init",
  1551. X *            above.
  1552. X *            "server" is the news server we got the
  1553. X *            response code from.
  1554. X *
  1555. X *    Returns:    -1 if the error is fatal (and we should exit).
  1556. X *            0 otherwise.
  1557. X *
  1558. X *    Side effects:    None.
  1559. X */
  1560. X
  1561. Xhandle_server_response(response, server)
  1562. Xint    response;
  1563. Xchar    *server;
  1564. X{
  1565. X    switch (response) {
  1566. X    case OK_NOPOST:        /* fall through */
  1567. X            printf(
  1568. X    "NOTE: This machine does not have permission to post articles.\n");
  1569. X        printf(
  1570. X    "      Please don't waste your time trying.\n\n");
  1571. X
  1572. X    case OK_CANPOST:
  1573. X        return (0);
  1574. X        break;
  1575. X
  1576. X    case ERR_ACCESS:
  1577. X        printf(
  1578. X   "This machine does not have permission to use the %s news server.\n",
  1579. X        server);
  1580. X        return (-1);
  1581. X        break;
  1582. X
  1583. X    default:
  1584. X        printf("Unexpected response code from %s news server: %d\n",
  1585. X            server, response);
  1586. X        return (-1);
  1587. X        break;
  1588. X    }
  1589. X    /*NOTREACHED*/
  1590. X}
  1591. X
  1592. X
  1593. X/*
  1594. X * put_server -- send a line of text to the server, terminating it
  1595. X * with CR and LF, as per ARPA standard.
  1596. X *
  1597. X *    Parameters:    "string" is the string to be sent to the
  1598. X *            server.
  1599. X *
  1600. X *    Returns:    Nothing.
  1601. X *
  1602. X *    Side effects:    Talks to the server.
  1603. X *
  1604. X *    Note:        This routine flushes the buffer each time
  1605. X *            it is called.  For large transmissions
  1606. X *            (i.e., posting news) don't use it.  Instead,
  1607. X *            do the fprintf's yourself, and then a final
  1608. X *            fflush.
  1609. X */
  1610. X
  1611. Xvoid
  1612. Xput_server(string)
  1613. Xchar *string;
  1614. X{
  1615. X#ifdef DEBUG
  1616. X    fprintf(stderr, ">>> %s\n", string);
  1617. X#endif
  1618. X    fprintf(ser_wr_fp, "%s\r\n", string);
  1619. X    (void) fflush(ser_wr_fp);
  1620. X}
  1621. X
  1622. X
  1623. X/*
  1624. X * get_server -- get a line of text from the server.  Strips
  1625. X * CR's and LF's.
  1626. X *
  1627. X *    Parameters:    "string" has the buffer space for the
  1628. X *            line received.
  1629. X *            "size" is the size of the buffer.
  1630. X *
  1631. X *    Returns:    -1 on error, 0 otherwise.
  1632. X *
  1633. X *    Side effects:    Talks to server, changes contents of "string".
  1634. X */
  1635. X
  1636. Xget_server(string, size)
  1637. Xchar    *string;
  1638. Xint    size;
  1639. X{
  1640. X    register char *cp;
  1641. X    char    *index();
  1642. X
  1643. X    if (fgets(string, size, ser_rd_fp) == NULL)
  1644. X        return (-1);
  1645. X
  1646. X    if ((cp = index(string, '\r')) != NULL)
  1647. X        *cp = '\0';
  1648. X    else if ((cp = index(string, '\n')) != NULL)
  1649. X        *cp = '\0';
  1650. X#ifdef DEBUG
  1651. X    fprintf(stderr, "<<< %s\n", string);
  1652. X#endif
  1653. X
  1654. X    return (0);
  1655. X}
  1656. X
  1657. X
  1658. X/*
  1659. X * close_server -- close the connection to the server, after sending
  1660. X *        the "quit" command.
  1661. X *
  1662. X *    Parameters:    None.
  1663. X *
  1664. X *    Returns:    Nothing.
  1665. X *
  1666. X *    Side effects:    Closes the connection with the server.
  1667. X *            You can't use "put_server" or "get_server"
  1668. X *            after this routine is called.
  1669. X */
  1670. X
  1671. Xvoid
  1672. Xclose_server()
  1673. X{
  1674. X    char    ser_line[256];
  1675. X
  1676. X    if (ser_wr_fp == NULL || ser_rd_fp == NULL)
  1677. X        return;
  1678. X
  1679. X    put_server("QUIT");
  1680. X    (void) get_server(ser_line, sizeof(ser_line));
  1681. X
  1682. X    (void) fclose(ser_wr_fp);
  1683. X    (void) fclose(ser_rd_fp);
  1684. X}
  1685. X
  1686. X#ifdef USG
  1687. Xbzero(p, l)
  1688. X    register char    *p;
  1689. X    register int    l;
  1690. X{
  1691. X    while (l-- > 0)
  1692. X        *p++ = 0;
  1693. X}
  1694. X#endif USG
  1695. END_OF_FILE
  1696.   if test 11231 -ne `wc -c <'inews/clientlib.c'`; then
  1697.     echo shar: \"'inews/clientlib.c'\" unpacked with wrong size!
  1698.   fi
  1699.   # end of 'inews/clientlib.c'
  1700. fi
  1701. if test -f 'prefix.c' -a "${1}" != "-c" ; then 
  1702.   echo shar: Will not clobber existing file \"'prefix.c'\"
  1703. else
  1704.   echo shar: Extracting \"'prefix.c'\" \(3041 characters\)
  1705.   sed "s/^X//" >'prefix.c' <<'END_OF_FILE'
  1706. X#include "config.h"
  1707. X
  1708. Ximport char *home_directory;
  1709. Ximport char *news_directory;
  1710. Ximport char *news_lib_directory;
  1711. Ximport char *master_directory;
  1712. Ximport char *help_directory;
  1713. Ximport char *bin_directory;
  1714. Ximport char *db_directory;
  1715. Ximport char *db_data_directory;
  1716. Ximport char *tmp_directory;
  1717. Ximport char *log_file;
  1718. X
  1719. X#define SHELL_PREFIX    0x01
  1720. X#define FULL_PREFIX    0x02
  1721. X#define CONF_PREFIX    0x04
  1722. X
  1723. Xstatic make_nn_prefix(flag, f)
  1724. Xint flag;
  1725. XFILE *f;
  1726. X{
  1727. X    char nl;
  1728. X    char buf[FILENAME], *p;
  1729. X    
  1730. X    nl = (flag & CONF_PREFIX) ? TAB : NL;
  1731. X
  1732. X    if (flag & SHELL_PREFIX) {
  1733. X#ifdef AVOID_SHELL_EXEC
  1734. X    fprintf(f, ":\n");
  1735. X#else
  1736. X    fprintf(f, "#!/bin/sh\n");
  1737. X#endif
  1738. X    fprintf(f, "\n# Generated by nn release %s at %s\n\n",
  1739. X           version_id, date_time((time_t)0));
  1740. X    }
  1741. X    fprintf(f, "VERSION=\"%s\"\n", version_id);
  1742. X
  1743. X#ifdef INEWS_PATH
  1744. X    strcpy(buf, INEWS_PATH);
  1745. X    fprintf(f, "INEWS=\"%s\"\n", buf);
  1746. X    if ((p = strrchr(buf, '/')) != NULL) *p = NUL;
  1747. X    fprintf(f, "INEWS_DIR=\"%s\"\n", buf);
  1748. X#else
  1749. X    fprintf(f, "INEWS=\"%s/inews\"\n", news_lib_directory);
  1750. X    fprintf(f, "INEWS_DIR=\"%s\"\n", news_lib_directory);
  1751. X#endif
  1752. X
  1753. X#ifndef OLD_AWK
  1754. X#define OLD_AWK "awk"
  1755. X#endif
  1756. X    fprintf(f, "AWK=\"%s\"\n", OLD_AWK);
  1757. X
  1758. X#ifdef NNTP
  1759. X    fprintf(f, "NNTP=true%c", nl);
  1760. X    fprintf(f, "ACTIVE=%s/ACTIVE\n", db_directory);
  1761. X#ifndef CACHE_DIRECTORY
  1762. X#define CACHE_DIRECTORY ""
  1763. X#endif
  1764. X    fprintf(f, "NNTPCACHE=%s\n", CACHE_DIRECTORY);
  1765. X#else
  1766. X    fprintf(f, "NNTP=false%c", nl);
  1767. X    fprintf(f, "ACTIVE=%s/active\n", news_lib_directory);
  1768. X#endif
  1769. X    fprintf(f, "LOG=%s\n", log_file);
  1770. X    fprintf(f, "TMP=${TMPDIR-%s}\n", tmp_directory);
  1771. X    fprintf(f, "DB=%s\n", db_directory);
  1772. X    fprintf(f, "BIN=%s\n", bin_directory);
  1773. X    fprintf(f, "LIB=%s\n", lib_directory);
  1774. X
  1775. X    if (flag & (FULL_PREFIX|CONF_PREFIX)) {
  1776. X    fprintf(f, "RECMAIL=\"%s\"\n", REC_MAIL);
  1777. X    fprintf(f, "SPOOL=%s\n", news_directory);
  1778. X    fprintf(f, "NLIB=%s\n", news_lib_directory);
  1779. X    fprintf(f, "MASTER=%s\n", master_directory);
  1780. X    fprintf(f, "HELP=%s\n", help_directory);
  1781. X    fprintf(f, "DBDATA=\"%s\"\n", db_data_directory ? db_data_directory : "");
  1782. X    fprintf(f, "OWNER=%s%c", OWNER, nl);
  1783. X    fprintf(f, "GROUP=%s\n", GROUP);
  1784. X    }
  1785. X
  1786. X    if (FULL_PREFIX) {
  1787. X    fprintf(f, "UMAN_DIR=\"%s\"\n", USER_MAN_DIR);
  1788. X    fprintf(f, "UMAN_SECT=\"%s\"\n", USER_MAN_SECTION);
  1789. X
  1790. X    fprintf(f, "SMAN_DIR=\"%s\"\n", SYS_MAN_DIR);
  1791. X    fprintf(f, "SMAN_SECT=\"%s\"\n", SYS_MAN_SECTION);
  1792. X
  1793. X    fprintf(f, "DMAN_DIR=\"%s\"\n", DAEMON_MAN_DIR);
  1794. X    fprintf(f, "DMAN_SECT=\"%s\"\n", DAEMON_MAN_SECTION);
  1795. X    }
  1796. X
  1797. X    if (flag & SHELL_PREFIX)
  1798. X    fprintf(f, "\n# ---- end of prefix\n\n");
  1799. X}
  1800. X
  1801. Xmain(argc, argv)
  1802. Xint argc;
  1803. Xchar *argv[];
  1804. X{
  1805. X    if (argc != 2) exit(2);
  1806. X
  1807. X    init_global(I_AM_MASTER);
  1808. X
  1809. X    switch (argv[1][0]) {
  1810. X     case 'f':
  1811. X    make_nn_prefix(SHELL_PREFIX|FULL_PREFIX, stdout);
  1812. X    break;
  1813. X     case 'p':
  1814. X    make_nn_prefix(SHELL_PREFIX, stdout);
  1815. X    break;
  1816. X     case 'c':
  1817. X    make_nn_prefix(CONF_PREFIX, stdout);
  1818. X    break;
  1819. X     default:
  1820. X    exit(1);
  1821. X    }
  1822. X    exit(0);
  1823. X}
  1824. X
  1825. Xnn_exit(n)
  1826. X{
  1827. X    exit(n);
  1828. X}
  1829. X
  1830. Xuser_error()
  1831. X{
  1832. X    exit(8);
  1833. X}
  1834. X
  1835. X#ifdef HAVE_JOBCONTROL
  1836. Xsuspend_nn()
  1837. X{}
  1838. X#endif
  1839. END_OF_FILE
  1840.   if test 3041 -ne `wc -c <'prefix.c'`; then
  1841.     echo shar: \"'prefix.c'\" unpacked with wrong size!
  1842.   fi
  1843.   # end of 'prefix.c'
  1844. fi
  1845. echo shar: End of archive 16 \(of 22\).
  1846. cp /dev/null ark16isdone
  1847. MISSING=""
  1848. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 ; do
  1849.     if test ! -f ark${I}isdone ; then
  1850.     MISSING="${MISSING} ${I}"
  1851.     fi
  1852. done
  1853. if test "${MISSING}" = "" ; then
  1854.     echo You have unpacked all 22 archives.
  1855.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1856. else
  1857.     echo You still must unpack the following archives:
  1858.     echo "        " ${MISSING}
  1859. fi
  1860. exit 0
  1861.